OS: Windows 10
Editor: Visual Studio Code
Rust version: 1.63.0
昨天認識Rust的記憶體管理機制,並依照官方文件用字串來了解其運作方式,但昨天注意到一個點,字串的宣告,範例是這樣宣告:
let s = String::from("hello");
那下面這樣宣告,看起來是字串,但實際是甚麼呢?
let x = "hello";
String
與string literal我們編譯看看讓Compiler告訴我們這是甚麼型別:
let x = "hello";
x.what_is_this_type();
Compiler給出了這樣的錯誤
Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0599]: no method named `what_is_this_type` found for reference `&str` in the current scope
--> src\main.rs:3:7
|
3 | x.what_is_this_type();
| ^^^^^^^^^^^^^^^^^ method not found in `&str`
For more information about this error, try `rustc --explain E0599`.
x
的型別是&str
,這個稱作string literal或是string slice,並不是String
。
str
,注意!沒有加&
運算符(operator)的,他是一個不可變的、動態的、存有UTF-8 type的序列集合。由於長度是未知的,他需要被作為指標進行處理,所以在宣告上通常會是&str
。
與str
不同的是,String
是可以支援隨意增減內容的UTF-8 type的型別。
用C++來類比的話,String
就是std::string
,裏頭有相當多的操作,不只是單純的序列集合;&str
則是char*
,是一個單純指標指向字符的序列。
上面有提到string slice這個詞,而slice則是Rust中的一個型別。
回到string slice來看,他會是某個字串的片段,僅額外包含了切片的容量與當前長度,以及一個指標指向原始資料,請看以下範例:
let s = "hello, world";
let hello = &s[0..5]; // hello
let world = &s[6..11]; // world
利用[起始index..結束index]
的方式我們可以抓出特定單字。
當然有一些省略對index的寫法:
let s = "hello, world";
let hello = &s[..5]; // hello
let world = &s[6..s.len()]; // world
let hello_world = &s[..]; // hello, world
因為slice是指向原始資料的指標,所以以下這個範例會產生錯誤:
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes(); // The type is &[u8]
// 利用迭代器把序列的index跟element抓出來
for (index, &element) in bytes.iter().enumerate() {
if element == b' ' {
return &s[0..index];
}
}
&s[..]
}
fn main() {
let mut s = String::from("hello, world");
let hello = first_word(&s);
s.clear(); // 錯誤! hello 指向 s 的第一個單字
println!("First word: {}", hello);
}